"""
OPC UA写入服务类
提供统一的写入接口，支持单个和批量写入操作，统一参数格式为(node_id, value, data_type)
"""


from typing import Dict, Any, Optional, Union, List
from enum import Enum
from dataclasses import dataclass
from ....utils.logger import get_logger, default_logger
logger = get_logger("driver.protocols")


# 定义有效的OPC UA数据类型列表
VALID_DATA_TYPES = {
    "Null", "Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
    "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
    "ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode",
    "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
    "Variant", "DiagnosticInfo"
}


class OpcUaICommandType(Enum):
    """
    OPC UA命令类型枚举
    对应OpcUaInterface.execute_command方法支持的命令类型
    """
    READ = "read"
    WRITE = "write"
    BROWSE = "browse"
    CALL = "call"


class OpcUaParamManager:
    """
    OPC UA参数管理器
    提供统一的参数管理接口，支持添加和获取不同格式的参数
    """

    def __new__(cls):
        """
        控制实例创建，防止外部创建新实例
        """
        if not hasattr(cls, '_instance'):
            cls._instance = super(OpcUaParamManager, cls).__new__(cls)
        return cls._instance

    def __init__(self):
        """
        初始化OPC UA参数管理器
        """
        # 使用双重检查确保只初始化一次
        if not hasattr(self, '_initialized'):
            # 直接存储参数，格式为 {node_id: (value, data_type)}
            self._params: Dict[Union[str, int], tuple] = {}
            self._receive_data_params: Dict[str, Any] = {}
            self._execute_command_params: Dict[OpcUaICommandType, Dict[str, Any]] = {}
            self._initialized = True

    def reset(self) -> None:
        """
        重置所有参数
        """
        self._params.clear()
        self._receive_data_params.clear()
        self._execute_command_params.clear()

    def add(self, node_id: Union[str, int], value: Any, data_type: Optional[str] = None) -> None:
        """
        添加参数

        Args:
            node_id: 节点ID
            value: 要写入的值
            data_type: 数据类型字符串
        """
        # 检查数据类型是否有效
        if data_type is not None:
            self._validate_data_type(data_type)
        self._params[node_id] = (value, data_type)

    def add_execute_command_param(self, command_type: OpcUaICommandType, *args, **kwargs) -> None:
        """
        添加execute_command方法参数

        Args:
            OpcUaICommandType: 命令类型枚举值
            *args: 简化参数形式
                - read: ("节点ID",)
                - write: ("节点ID", 值, "数据类型")
                - browse: ("节点ID",)（可选）
                - call: ("方法ID", "父节点ID", ["参数列表"])
            **kwargs: 命令参数（向后兼容）
                - read: {"node_id": "节点ID"}
                - write: {"node_id": "节点ID", "value": 值, "data_type": "数据类型"}
                - browse: {"node_id": "节点ID"}（可选）
                - call: {"method_id": "方法ID", "parent_id": "父节点ID", "args": ["参数列表"]}
        """
        if not isinstance(command_type, OpcUaICommandType):
            raise ValueError("command_type必须是OpcUaICommandType枚举类型")

        # 如果提供了args，则根据command_type解析args
        if args:
            if command_type == OpcUaICommandType.READ and len(args) >= 1:
                kwargs = {"node_id": args[0]}
            elif command_type == OpcUaICommandType.WRITE and len(args) >= 2:
                kwargs = {"node_id": args[0], "value": args[1]}
                if len(args) >= 3:
                    kwargs["data_type"] = args[2]
            elif command_type == OpcUaICommandType.BROWSE and len(args) >= 1:
                kwargs = {"node_id": args[0]}
            elif command_type == OpcUaICommandType.CALL and len(args) >= 3:
                kwargs = {"method_id": args[0], "parent_id": args[1], "args": args[2]}
            else:
                raise ValueError(f"参数数量不匹配命令类型: {command_type}")

        self._execute_command_params[command_type] = kwargs

    def _validate_data_type(self, data_type: str) -> None:
        """
        验证数据类型是否有效

        Args:
            data_type: 要验证的数据类型字符串

        Raises:
            ValueError: 当数据类型不在有效类型列表中时抛出异常
        """
        if data_type not in VALID_DATA_TYPES:
            raise ValueError(f"不支持的数据类型: {data_type}。有效类型包括: {', '.join(sorted(VALID_DATA_TYPES))}")



    def get_write_batch_param(self) -> Dict[Union[str, int], Any]:
        """
        获取write_batch方法所需的参数格式

        Returns:
            Dict[Union[str, int], Any]: write_batch方法所需的参数
        """
        all_params = {}
        for node_id, (value, data_type) in self._params.items():
            if data_type:
                all_params[node_id] = {
                    "value": value,
                    "data_type": data_type
                }
            else:
                all_params[node_id] = value

        return all_params


    def get_send_data_param(self) -> Dict[Union[str, int], Any]:
        """
        获取send_data方法所需的参数格式

        Returns:
            Dict[Union[str, int], Any]: send_data方法所需的参数字典，
                                       键为节点ID，值为要写入的值
        """
        send_data_params = {}
        for node_id, (value, data_type) in self._params.items():
            if data_type:
                send_data_params[node_id] = {
                    "value": value,
                    "data_type": data_type
                }
            else:
                send_data_params[node_id] = value

        return send_data_params

    def get_execute_command_param(self, command_type: OpcUaICommandType) -> Dict[str, Any]:
        """
        获取execute_command方法所需的参数格式

        Args:
            OpcUaICommandType: 命令类型枚举值

        Returns:
            Dict[str, Any]: execute_command方法所需的参数
        """
        if not isinstance(command_type, OpcUaICommandType):
            raise ValueError("command_type必须是OpcUaICommandType枚举类型")

        return self._execute_command_params.get(command_type, {})


def get_opcua_param_manager() -> OpcUaParamManager:
    """
    获取OPC UA参数管理器实例（全局访问点）

    Returns:
        OpcUaParamManager: OPC UA参数管理器实例
    """
    return OpcUaParamManager()